﻿using System;
using System.Linq;
using System.Collections.Generic;
using System.Xml.Linq;
using System.ServiceModel;

namespace EcodexIntegrationSample
{
    class MainController
    {
        private View.IMain _view;
        private Random _random;

        private enum TipoComprobante
        {
            cfdi = 1,
            Retenciones = 2
        }

        /// <summary>
        /// This id can come from a database or be hard coded 
        /// by each service integrator or service reseller.
        /// </summary>
        //private const String INTEGRATOR_ID = "123";


        public MainController(View.IMain view)
        {
            _view = view;
            _view.UniTestDummyXMLString += _view_UniTestDummyXMLString;
            _view.GenerateXMLFile += _view_GenerateXMLFile;
            _view.GetInvoice += _view_GetInvoice;
            _view.GetStatus += _view_GetStatus;
            _view.GetStatusClient += _view_GetStatusClient;            
            _view.StampService += _view_StampService;
            _view.AsignarTimbres += _view_AsignarTimbres;
            _view.AltaEmisor += _view_AltaEmisor;
            _view.RecuperaAcuse += _view_RecuperaAcuse;
            _view.CancelaOtros += _view_CancelaOtros;
            _view.CancelaMultiple += _view_CancelaMultiple;
            _view.CargaCertificadosLocal += _view_CargaCertificadosLocal;
            _view.ObtenerClaveCargaCertificados += _view_ObtenerClaveCargaCertificados;
            _view.ObtenerToken += _view_ObtenerToken;
            _view.ObtenerComprobantePorHash += _view_ObtenerComprobantePorHash;
            _view.ObtenerUltimosDocumentosTimbrados+=_view_ObtenerUltimosDocumentosTimbrados;
            _view.CancelarTimbrado += _view_CancelarTimbrado;
            _random = new Random();
        }

        void _view_CancelarTimbrado(object sender, EventArgs e)
        {
            using (var ioForm = new Forms.frmCancelarTimbrado())
            {
                ioForm.ShowDialog();
            }
        }

        void _view_ObtenerUltimosDocumentosTimbrados(object sender, EventArgs e)
        {
            using (var ioForm = new Forms.frmObtenerUltimosDocumentosTimbrados())
            {
                ioForm.ShowDialog();
            }
        }
    
        void _view_ObtenerToken(object sender, EventArgs e)
        {
            using (var ioForm = new Forms.frmObtenerTokenyHora())
            {
                ioForm.ShowDialog();
            }
        }

        void _view_ObtenerComprobantePorHash(object sender, EventArgs e)
        {
            using (var ioForm = new Forms.frmObtenerTimbradoPorHash())
            {
                ioForm.ShowDialog();
            }
        }

        void _view_ObtenerClaveCargaCertificados(object sender, EventArgs e)
        {
            using (var ioForm = new Forms.frmObtenerTokenAltaCertificados())
            {
                ioForm.ShowDialog();
            }
        }

        void _view_CargaCertificadosLocal(object sender, EventArgs e)
        {
            using (var ioForm = new Forms.frmCargaCertificados())
            {
                ioForm.ShowDialog();
            }
        }
        void _view_StampService(object sender, EventArgs e)
        {
            using (var ioForm = new Forms.frmTimbradoXMLFile())
            {
                ioForm.ShowDialog();
            }
        }

        void _view_AsignarTimbres(object sender, EventArgs e)
        {
            using (var ioForm = new Forms.frmAsignarTimbresEmisor())
            {
                ioForm.ShowDialog();
            }
        }

        void _view_AltaEmisor(object sender, EventArgs e)
        {
            using (var ioForm = new Forms.frmAltaEmisor())
            {
                ioForm.ShowDialog();
            }
        }

        void _view_RecuperaAcuse(object sender, EventArgs e)
        {
            using (var ioForm = new Forms.frmRecuperaAcuseCancelacion())
            {
                ioForm.ShowDialog();
            }
        }

        void _view_CancelaOtros(object sender, EventArgs e)
        {
            using (var ioForm = new Forms.frmCancelaOtros())
            {
                ioForm.ShowDialog();
            }
        }

        void _view_CancelaMultiple(object sender, EventArgs e)
        {
            using (var ioForm = new Forms.frmCancelaMultiple())
            {
                ioForm.ShowDialog();
            }
        }

        void _view_GenerateXMLFile(object sender, EventArgs e)
        {
            using (var ioForm = new Forms.frmTimbradoXMLFile())
            {
                ioForm.ShowDialog();
            }
        }

        
        void _view_UniTestDummyXMLString(object sender, EventArgs e)
        {
            Utils.Utilerias Util = new Utils.Utilerias(_view);
            
            long transactionID = _random.Next();
            var token = String.Empty;
            string Error;
            String comprobanteSellado  = String.Empty;
            TipoComprobante tipocomprobante;
            
            if (((System.Windows.Forms.Button)sender).Name == "testXMLButton")
            {
                tipocomprobante = TipoComprobante.cfdi;
                comprobanteSellado = GenerarCfdiDummy();
            }
            else
            {
                tipocomprobante = TipoComprobante.Retenciones;
                comprobanteSellado = GenerarRetencionDummy();
            }

            Error = Util.CreateToken(Util.RFC, transactionID, ref token);
            if (!string.IsNullOrEmpty(Error))
            {
                _view.ShowUnknownError(Error);
                return;
            }
            
            try
            {
                transactionID = _random.Next();               
                var invoiceXML = new SrvTimbrado.ComprobanteXML
                {
                    DatosXML = comprobanteSellado
                };
                using (var invoiceSrv = new SrvTimbrado.TimbradoClient())
                {
                    var advertencias = invoiceSrv.TimbraXML(ref invoiceXML, Util.RFC, token, ref transactionID);
                    _view.ResultStr = invoiceXML.DatosXML;
                    if (tipocomprobante == TipoComprobante.cfdi)
                        GenerarQR(invoiceXML.DatosXML, token);
                }   
                
            }
            #region Invoice service exceptions
            catch (FaultException<SrvTimbrado.FallaServicio> serviceFault)
            {
                using (var errorForm = new Forms.Error(TranslateFault.ToServiceError(serviceFault.Detail)))
                {
                    errorForm.ShowDialog();
                }
            }
            catch (FaultException<SrvTimbrado.FallaSesion> sessionFauld)
            {
                using (var errorForm = new Forms.Error(TranslateFault.ToSessionError(sessionFauld.Detail)))
                {
                    errorForm.ShowDialog();
                }                
            }
            catch (FaultException<SrvTimbrado.FallaValidacion> validationFault)
            {
                using (var errorForm = new Forms.Error(TranslateFault.ToValidationError(validationFault.Detail)))
                {
                    errorForm.ShowDialog();
                }
            }
            #endregion
            catch (TimeoutException)
            {
                _view.ShowUnknownError("Error de tiempo de espera del servicio");
            }
            catch (Exception ex)
            {
                _view.ShowUnknownError(ex.Message);
            }
        }

        string GenerarCfdiDummy()
        {
            Utils.Utilerias Util = new Utils.Utilerias(_view);
            Utils.GeneradorSello generador = new Utils.GeneradorSello();
            String Fecha = String.Format("{0:s}", DateTime.Now);
            //CFDI
            String ComprobanteSinSello =                
                    String.Format("<?xml version=\"1.0\" encoding=\"utf-8\"?><cfdi:Comprobante xmlns:cfdi=\"http://www.sat.gob.mx/cfd/3\" xmlns:donat=\"http://www.sat.gob.mx/donat\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" fecha=\"{0}\" version=\"3.2\" xsi:schemaLocation=\"http://www.sat.gob.mx/cfd/3 http://www.sat.gob.mx/sitio_internet/cfd/3/cfdv32.xsd\" serie=\"8\" folio=\"3\" formaDePago=\"PAGO EN UNA SOLA EXHIBICION\" metodoDePago=\"Efectivo\" noCertificado=\"{2}\" subTotal=\"7069.00\" TipoCambio=\"1\" Moneda=\"PESO\" total=\"8200.04\" tipoDeComprobante=\"ingreso\" NumCtaPago=\"123456\"  LugarExpedicion=\"manzanillo\"  FolioFiscalOrig=\"23480727-43C3-40C4-A866-356152786D86\" SerieFolioFiscalOrig=\"A\" FechaFolioFiscalOrig=\"2011-12-18T00:00:00\" MontoFolioFiscalOrig=\"125.21\"><cfdi:Emisor rfc=\"{1}\" nombre=\"INTEGRADORA ADUANAL Y DE SERVICIOS WOODWARD S.C.\">  <cfdi:DomicilioFiscal calle=\"AV. TENIENTE AZUETA\" noExterior=\"25-1\" colonia=\"BUROCRATA\" localidad=\"MANZANILLO\" municipio=\"MANZANILLO\" estado=\"COLIMA\" pais=\"MEXICO\" codigoPostal=\"28250\"/><cfdi:RegimenFiscal Regimen=\"regimen 1\" /><cfdi:RegimenFiscal Regimen=\"regimen 2\" /></cfdi:Emisor><cfdi:Receptor rfc=\"XEXX010101000\" nombre=\"TRADING SERVICES CORPORATION.\">  <cfdi:Domicilio calle=\"1705 E HILLSIDE RD STE.\" noExterior=\"1\" localidad=\"LAREDO\" referencia=\"LAREDO\" municipio=\"LAREDO\" estado=\"TEXAS\" pais=\"USA\" codigoPostal=\"78041\"/></cfdi:Receptor><cfdi:Conceptos>  <cfdi:Concepto cantidad=\"1\" unidad=\"SERVICIO\" descripcion=\"inicio SERVICIOS COMPLEMENTARIOS\" valorUnitario=\"2000.00\" importe=\"2000.00\"/></cfdi:Conceptos><cfdi:Impuestos totalImpuestosTrasladados=\"1131.04\">  <cfdi:Traslados>    <cfdi:Traslado impuesto=\"IVA\" tasa=\"16\" importe=\"1131.04\"/>  </cfdi:Traslados></cfdi:Impuestos></cfdi:Comprobante>", Fecha, Util.RFC, Util.NoCertificado);
            return generador.xmlSelladoCfdi(Util.RFC, Util.NoCertificado, ComprobanteSinSello); 
        }

        string GenerarRetencionDummy()
        {
            Utils.Utilerias Util = new Utils.Utilerias(_view);
            Utils.GeneradorSello generador = new Utils.GeneradorSello();
            String Fecha = String.Format("{0:s}", DateTime.Now) + "-06:00";
            //Retenciones
            String RetencionSinSello =
                String.Format(@"<?xml version=""1.0"" encoding=""utf-8""?><retenciones:Retenciones xmlns:retenciones=""http://www.sat.gob.mx/esquemas/retencionpago/1"" xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xsi:schemaLocation=""http://www.sat.gob.mx/esquemas/retencionpago/1 retencionpagov1.xsd"" Version=""1.0"" CveRetenc=""18"" DescRetenc=""Pagos realizados a favor de residentes en el extranjero."" FolioInt=""1"" FechaExp=""{0}"" Cert=""sincertificado"" NumCert=""{1}"" Sello=""sinsello""><retenciones:Emisor RFCEmisor=""{2}"" NomDenRazSocE=""HAZ DF SC""/><retenciones:Receptor Nacionalidad=""Extranjero""><retenciones:Extranjero NomDenRazSocR=""DOSTUFF MEDIA LLC""/></retenciones:Receptor><retenciones:Periodo MesIni=""02"" MesFin=""12"" Ejerc=""2014""/><retenciones:Totales montoTotOperacion=""151085.00"" montoTotGrav=""0.00"" montoTotExent=""151085.00"" montoTotRet=""0.00""><retenciones:ImpRetenidos Impuesto=""01"" montoRet=""0.00"" TipoPagoRet=""Pago definitivo""/></retenciones:Totales></retenciones:Retenciones>", Fecha, Util.NoCertificado, Util.RFC);                    
            return generador.xmlSelladoRetencion(Util.RFC, Util.NoCertificado, RetencionSinSello);
        }

        void GenerarQR(String DatosXML, String token)
        {
            Utils.Utilerias Util = new Utils.Utilerias(_view);

            #region Optional steep to get the QR barcode image
            Int64 transactionID = _random.Next();
            XDocument doc = new XDocument();
            doc = XDocument.Parse(DatosXML);
            XElement singature = new XElement("{http://www.sat.gob.mx/TimbreFiscalDigital}TimbreFiscalDigital");
            string uuid = doc.Root.Descendants(singature.Name).ToArray()[0].Attribute("UUID").Value;
            using (var repositorySrv = new SrvRepository.RepositorioClient())
            {
                var infoQR = repositorySrv.ObtenerQR(Util.RFC, token, ref transactionID, uuid);
                var ms = new System.IO.MemoryStream(infoQR.Imagen);
                _view.BarcodeQR = new System.Drawing.Bitmap(ms);
            }
            #endregion
        }

        void _view_GetInvoice(object sender, EventArgs e)
        {
            using (var ioForm = new Forms.frmComprobante())
            {
                ioForm.ShowDialog();
            }
        }
        void _view_GetStatus(object sender, EventArgs e)
        {
            using (var ioForm = new Forms.GetStatus())
            {
                ioForm.ShowDialog();
            }
        }
        void _view_GetStatusClient(object sender, EventArgs e)
        {
            using (var ioForm = new Forms.frmGetStatusClient())
            {
                ioForm.ShowDialog();
            }
        }       
    }
}
